package butterknife.internal;

import butterknife.internal.util.Const;
import butterknife.internal.util.LogUtil;
import butterknife.internal.util.TextUtils;
import ohos.agp.components.Component;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.PixelMapElement;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.text.Font;
import ohos.app.Context;
import ohos.global.resource.*;
import ohos.media.image.ImageSource;
import ohos.media.image.PixelMap;

import java.io.*;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;

import static butterknife.internal.util.ResUtil.getPathById;

@SuppressWarnings("WeakerAccess") // Used by generated code.
public final class Utils {

  private static final int BUFFER_LENGTH = 8192;
  public static final int DEFAULT_ERROR = -1;
  private static final String RAW_FILE_PATH = "entry/resources/rawfile/";
  private static final String TAG = Utils.class.getCanonicalName();

  public static Element getTintedElement(Context context, int id, int tintAttrId) throws IOException, NotExistException, WrongTypeException {
    /*boolean attributeFound = context.getTheme().resolveAttribute(tintAttrId, VALUE, true);
    if (!attributeFound) {
      throw new Resources.NotFoundException("Required tint color attribute with name"
              + context.getResourceManager().getResource(tintAttrId)
              + " and attribute ID "
              + tintAttrId+
              " was not found.");
    }*/
    ResourceManager manager = context.getResourceManager();
    ShapeElement drawable = new ShapeElement();
    // drawable = DrawableCompat.wrap(drawable.mutate());


    int color;
    try {
      color = context.getResourceManager().getElement(id).getColor();
    } catch (WrongTypeException e) {
      if (e.getMessage() != null)
        LogUtil.error(TAG, e.getMessage());
    }
    //DrawableCompat.setTint(drawable, color);
    return drawable;
  }

  public static Element getDrawable(Context context, int id){

    Optional<PixelMap> optional = getPixelMap(context, id);
    return optional.map(PixelMapElement::new).orElse(null);

  }

  private static Optional<PixelMap> getPixelMap(Context context, int id) {
    String path = getPathById(context, id);
    if (TextUtils.isEmpty(path)) {
      LogUtil.error(TAG, "getPixelMap -> get empty path");
      return Optional.empty();
    }
    RawFileEntry assetManager = context.getResourceManager().getRawFileEntry(path);
    ImageSource.SourceOptions options = new ImageSource.SourceOptions();
    options.formatHint = "image/png";
    ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();
    try {
      Resource asset = assetManager.openRawFile();
      ImageSource source = ImageSource.create(asset, options);
      return Optional.ofNullable(source.createPixelmap(decodingOptions));
    } catch (IOException e) {
      LogUtil.error(TAG, "getPixelMap -> IOException");
    }
    return Optional.empty();

  }

  @SafeVarargs
  public static <T> T[] arrayFilteringNull(T... views) {
    int end = 0;
    int length = views.length;
    for (int i = 0; i < length; i++) {
      T view = views[i];
      if (view != null) {
        views[end++] = view;
      }
    }
    return end == length
            ? views
            : Arrays.copyOf(views, end);
  }

  @SafeVarargs
  public static <T> List<T> listFilteringNull(T... views) {
    return new ImmutableList<>(arrayFilteringNull(views));
  }

  public static Component findRequiredView(Component source, int id, String who) {
    Component view = source.findComponentById(id);
    if (view != null) {
      return view;
    }
    String name = getResourceEntryName(source, id);
    throw new IllegalStateException("Required view '"
        + name
        + "' with ID "
        + id
        + " for "
        + who
        + " was not found. If this view is optional add '@Nullable' (fields) or '@Optional'"
        + " (methods) annotation.");
  }

  public static <T> T findRequiredViewAsType(Component source, int id, String who,
      Class<T> cls) {
    Component view = findRequiredView(source, id, who);

    return castView(view, id, who, cls);
  }

  public static <T> T castView(Component view, int id, String who, Class<T> cls) {
    try {
      return cls.cast(view);
    } catch (ClassCastException e) {
      String name = getResourceEntryName(view, id);
      throw new IllegalStateException("View '"
          + name
          + "' with ID "
          + id
          + " for "
          + who
          + " was of the wrong type. See cause for more info.", e);
    }
  }

  private static String getResourceEntryName(Component view, int id) {
    try {
      return view.getContext().getResourceManager().getIdentifier(id);
    } catch (IOException e) {
      if (e.getMessage() != null)
        LogUtil.error(TAG, e.getMessage());
    } catch (NotExistException e) {
      if (e.getMessage() != null)
        LogUtil.error(TAG, e.getMessage());
    }
    return "";
  }

  private Utils() {
    throw new AssertionError("No instances.");
  }

  /**
   * get string
   *
   * @param context the context
   * @param id the string id
   * @return string of the given id
   */
  public static String getString(Context context, int id) {
    String result = "";
    if (context == null) {
      LogUtil.error(TAG, "getString -> get null context");
      return result;
    }
    ResourceManager manager = context.getResourceManager();
    if (manager == null) {
      LogUtil.error(TAG, "getString -> get null ResourceManager");
      return result;
    }
    try {
      result = manager.getElement(id).getString();
    } catch (IOException e) {
      LogUtil.error(TAG, "getString -> IOException");
    } catch (NotExistException e) {
      LogUtil.error(TAG, "getString -> NotExistException");
    } catch (WrongTypeException e) {
      LogUtil.error(TAG, "getString -> WrongTypeException");
    }
    return result;
  }

  /**
   * get the color
   *
   * @param context the context
   * @param id the id
   * @return the color
   */
  public static int getColor(Context context, int id) {
    int result = 0;
    if (context == null) {
      LogUtil.error(TAG, "getColor -> get null context");
      return result;
    }
    ResourceManager manager = context.getResourceManager();
    if (manager == null) {
      LogUtil.error(TAG, "getColor -> get null ResourceManager");
      return result;
    }
    try {
      result = manager.getElement(id).getColor();
    } catch (IOException e) {
      LogUtil.error(TAG, "getColor -> IOException");
    } catch (NotExistException e) {
      LogUtil.error(TAG, "getColor -> NotExistException");
    } catch (WrongTypeException e) {
      LogUtil.error(TAG, "getColor -> WrongTypeException");
    }
    return result;
  }

  /**
   * get the int
   *
   * @param context the context
   * @param id the int array
   * @return the int array
   */
  public static int getInteger(Context context, int id) {
    int result = 0;
    if (context == null) {
      LogUtil.error(TAG, "getInt -> get null context");
      return result;
    }
    ResourceManager manager = context.getResourceManager();
    if (manager == null) {
      LogUtil.error(TAG, "getInt -> get null ResourceManager");
      return result;
    }
    try {
      result = manager.getElement(id).getInteger();
    } catch (IOException e) {
      LogUtil.error(TAG, "getInt -> IOException");
    } catch (NotExistException e) {
      LogUtil.error(TAG, "getInt -> NotExistException");
    } catch (WrongTypeException e) {
      LogUtil.error(TAG, "getInt -> WrongTypeException");
    }
    return result;
  }

  /**
   * get the boolean value
   *
   * @param context the context
   * @param id the id
   * @return get the boolean dimen value
   */
  public static boolean getBoolean(Context context, int id) {
    boolean result = false;
    if (context == null) {
      LogUtil.error(TAG, "getBoolean -> get null context");
      return result;
    }
    ResourceManager manager = context.getResourceManager();
    if (manager == null) {
      LogUtil.error(TAG, "getBoolean -> get null ResourceManager");
      return result;
    }
    try {
      result = manager.getElement(id).getBoolean();
    } catch (IOException e) {
      LogUtil.error(TAG, "getBoolean -> IOException");
    } catch (NotExistException e) {
      LogUtil.error(TAG, "getBoolean -> NotExistException");
    } catch (WrongTypeException e) {
      LogUtil.error(TAG, "getBoolean -> WrongTypeException");
    }
    return result;
  }

  /**
   * get the dimen value
   *
   * @param context the context
   * @param id the id
   * @return get the float dimen value
   */
  public static float getDimen(Context context, int id) {
    float result = 0;
    if (context == null) {
      LogUtil.error(TAG, "getDimen -> get null context");
      return result;
    }
    ResourceManager manager = context.getResourceManager();
    if (manager == null) {
      LogUtil.error(TAG, "getDimen -> get null ResourceManager");
      return result;
    }
    try {
      result = manager.getElement(id).getFloat();
    } catch (IOException e) {
      LogUtil.error(TAG, "getDimen -> IOException");
    } catch (NotExistException e) {
      LogUtil.error(TAG, "getDimen -> NotExistException");
    } catch (WrongTypeException e) {
      LogUtil.error(TAG, "getDimen -> WrongTypeException");
    }
    return result;
  }

  /**
   * get the dimen value
   *
   * @param context the context
   * @param id the id
   * @return get the int dimen value
   */
  public static int getIntDimen(Context context, int id) {
    float value = getDimen(context, id);
    return (int) (value >= 0 ? value + Const.FLOAT_HALF : value - Const.FLOAT_HALF);
  }

    /**
     * get the string array
     *
     * @param context the context
     * @param id the string array id
     * @return the string array
     */
    public static String[] getStringArray(Context context, int id) {
        String[] result = null;
        if (context == null) {
            LogUtil.error(TAG, "getStringArray -> get null context");
            return result;
        }
        ResourceManager manager = context.getResourceManager();
        if (manager == null) {
            LogUtil.error(TAG, "getStringArray -> get null ResourceManager");
            return result;
        }
        try {
            result = manager.getElement(id).getStringArray();
        } catch (IOException e) {
            LogUtil.error(TAG, "getStringArray -> IOException");
        } catch (NotExistException e) {
            LogUtil.error(TAG, "getStringArray -> NotExistException");
        } catch (WrongTypeException e) {
            LogUtil.error(TAG, "getStringArray -> WrongTypeException");
        }
        return result;
    }

  /**
   * get the int array
   *
   * @param context the context
   * @param id the string array id
   * @return the string array
   */
  public static int[] getIntArray(Context context, int id) {int[] result = null;
    if (context == null) {
      LogUtil.error(TAG, "getIntArray -> get null context");
      return result;
    }
    ResourceManager manager = context.getResourceManager();
    if (manager == null) {
      LogUtil.error(TAG, "getIntArray -> get null ResourceManager");
      return result;
    }
    try {
      result = manager.getElement(id).getIntArray();
    } catch (IOException e) {
      LogUtil.error(TAG, "getIntArray -> IOException");
    } catch (NotExistException e) {
      LogUtil.error(TAG, "getIntArray -> NotExistException");
    } catch (WrongTypeException e) {
      LogUtil.error(TAG, "getIntArray -> WrongTypeException");
    }
    return result;
  }

  public static Font getFont(Context context, int fontId, int style, boolean italic) {
    String fontFamily = getString(context, fontId);
    String path = RAW_FILE_PATH + fontFamily;
    File file = new File(context.getDataDir(), fontFamily);
    try (OutputStream outputStream = new FileOutputStream(file);
         InputStream inputStream = context.getResourceManager().getRawFileEntry(path).openRawFile()) {
      byte[] buffer = new byte[BUFFER_LENGTH];
      int bytesRead = inputStream.read(buffer, 0, BUFFER_LENGTH);
      while (bytesRead != DEFAULT_ERROR) {
        outputStream.write(buffer, 0, bytesRead);
        bytesRead = inputStream.read(buffer, 0, BUFFER_LENGTH);
      }
    } catch (FileNotFoundException exception) {
      LogUtil.error(TAG, "loadFontFromFile -> FileNotFoundException : " + exception.getLocalizedMessage());
    } catch (IOException exception) {
      LogUtil.error(TAG, "loadFontFromFile -> IOException : " + exception.getLocalizedMessage());
    }
    return Optional.of(new Font.Builder(file).setWeight(style/*Font.REGULAR*/).makeItalic(italic).build()).get();
  }

}
